home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C -*- */
- /* Terminal.cc - Terminal class implementation
- * Inspired by the User Interface Manager code in chapter
- * 12 of "C++, a guide for C programmers", by Sharam Hekmatpour,
- * (c) 1990 by Prentice Hall of Australia Pty Ltd.
- * Created by Robert Heller on Sat Dec 7 22:05:49 1991
- *
- * ------------------------------------------------------------------
- * Home Libarian by Deepwoods Software
- * Common Class library implementation code
- * ------------------------------------------------------------------
- * Modification History:
- * ------------------------------------------------------------------
- * Contents:
- * ------------------------------------------------------------------
- *
- *
- * Copyright (c) 1991,1992 by Robert heller (D/B/A Deepwoods Software)
- * All Rights Reserved
- *
- */
- #include <Terminal.h>
-
- #ifndef MESSYDOS
- // Globals used by termcap library...
- // (Weirdness of OSK's termcap library...)
- #ifdef OSK
- char PC_;
- #else
- char PC;
- #endif
- char* BC;
- char* UP;
- #ifdef unix
- unsigned int ospeed;
- #else
- short ospeed;
- #endif
- #endif
-
- #ifdef unix
- #include <stdio.h>
- #include <signal.h>
- #endif
-
- short Terminal::cline; // current line
- short Terminal::ccol; // current column
- short Terminal::lines; // screen lines
- short Terminal::colms; // screen columns
- ErrFun Terminal::errFun;
- char Terminal::termBuf[bufSize];
- Terminal* Terminal::term;
- #ifdef OSK
- sgbuf Terminal::ttym;
- sgbuf Terminal::xttym;
- #endif
- #ifdef unix
- struct termios Terminal::ttym;
- struct termios Terminal::xttym;
- #endif
-
- #ifndef MESSYDOS
- char Terminal::TermType[48]; // terminal type name
- char Terminal::TCapBuf[TCapsLen]; // termcap buffer
- char Terminal::tcapbuf[TCapsLen]; // copy
- // termcap capabilities
- char* Terminal::BC; // backspace character
- char* Terminal::UP; // up line sequence
- char* Terminal::CL; // clear screen
- char* Terminal::CM; // cursor movement
- char* Terminal::CE; // clear to eol
- char* Terminal::CD; // clear to eos
- char* Terminal::SO; // standout start
- char* Terminal::SE; // standout end
- char* Terminal::HO; // home cursor
- char* Terminal::KD; // down arrow key
- char* Terminal::KU; // up arrow key
- char* Terminal::KR; // right arrow key
- char* Terminal::KL; // left arrow key
- char* Terminal::KH; // home key
- char* Terminal::KB; // backspace key
- char* Terminal::TI; // terminal init
- char* Terminal::TE; // terminal de-init
- short Terminal::ospeed; // baud rate (used for padding)
- char Terminal::PC; // pad character
- #endif
-
- // Interrupt handler...
- int Interrupt()
- {
- Terminal::term->PlainPen();
- Terminal::term->ExitChars();
- #ifdef OSK
- _ss_opt(0, &(Terminal::ttym));
- intercept(0);
- #endif
- #ifdef unix
- tcsetattr(0, TCSANOW, &(Terminal::ttym));
- signal(SIGINT,0);
- #endif
- exit(1);
- return(0);
- }
-
-
- #ifdef OSK
- // This is how signals are handled by OSK programs...
- static void Intercept(int sig)
- {
- if (sig == SIGINT) Interrupt();
- return;
- }
- #endif
-
- // Constructor: fetch terminal type, termcap info, and initialize terminal
- Terminal::Terminal ()
- {
- char* temp;
-
- // make sure called only once
- if (term != 0) Error(termErr,"in Terminal");
- term = this; // self reference
- #ifdef MESSYDOS
- gppconio_init();
- text_info screen_info;
- gettextinfo(&screen_info);
- lines = screen_info.screenheight;
- colms = screen_info.screenwidth;
- cline = 0;
- ccol = 0;
- PlainPen();
- #else
- SE = ""; // (set here so Error won't crash)
- #ifdef OSK
- // Get vanila terminal modes
- if (_gs_opt(0, &ttym) < 0) Error(sysErr,"for _gs_opt");
- #endif
- #ifdef unix
- // Get vanila terminal modes
- if (tcgetattr(0, &ttym) < 0) Error(sysErr,"for tcgetattr");
- #endif
- // Get terminal type
- char *tt = getenv("TERM");
- // Unknown?? give up...
- if (tt == 0) Error(sysErr,"Env. TERM not set!");
- // remember type...
- strcpy(TermType,tt);
- // Fetch termcap entry...
- if (tgetent(TCapBuf,TermType) <= 0)
- Error(sysErr,"Unknown Terminal Type!");
- // Fetch needed caps.
- char* ptr = tcapbuf;
- // pad character:
- #ifdef OSK
- if (temp = tgetstr("pc",&ptr)) {
- PC = PC_ = *temp;
- } else PC = PC_ = 0;
- #else
- if (temp = tgetstr("pc",&ptr)) {
- PC = PC = *temp;
- } else PC = PC = 0;
- #endif
- ::BC = BC = tgetstr("bc",&ptr); // backspace:
- if (BC == 0) ::BC = BC = "\010"; // make sure it is something
- ::UP = UP = tgetstr("up",&ptr); // up line
- CL = tgetstr("cl",&ptr); // clear display
- CM = tgetstr("cm",&ptr); // cursor movement
- CE = tgetstr("ce",&ptr); // clear to EOL
- CD = tgetstr("cd",&ptr); // clear to EOS
- SO = tgetstr("so",&ptr); // standout begin
- SE = tgetstr("se",&ptr); // standout end
- HO = tgetstr("ho",&ptr); // home cursor
- KD = tgetstr("kd",&ptr); // down arrow key
- KU = tgetstr("ku",&ptr); // up arrow key
- KR = tgetstr("kr",&ptr); // right arrow key
- KL = tgetstr("kl",&ptr); // left arrow key
- KH = tgetstr("kh",&ptr); // home key
- KB = tgetstr("kb",&ptr); // backspace key
- TI = tgetstr("ti",&ptr); // term init string
- TE = tgetstr("te",&ptr); // term de-init string
- lines = tgetnum("li"); // lines
- colms = tgetnum("co"); // columns
- #ifdef OSK
- ::ospeed = ospeed = ttym.sg_baud; // baud rate
- #endif
- #ifdef unix
- ::ospeed = ospeed = cfgetospeed(&ttym);
- #endif
- // handle missing features
- if (CE == 0) CE = "\007";
- if (SO == 0) SO = "";
- if (SE == 0) SE = "";
- if (TI == 0) TI = "";
- if (TE == 0) TE = "";
- if (KD == 0) KD = "\016"; // ^N
- if (KU == 0) KU = "\020"; // ^P
- if (KR == 0) KR = "\006"; // ^F
- if (KL == 0) KL = "\002"; // ^B
- if (KH == 0) {
- if (KD[0] == '\033' || KU[0] == '\033' ||
- KR[0] == '\033' || KL[0] == '\033')
- KH = "\033\033"; // ESC-ESC (^[^[)
- else KH = "\033"; // ESC (^[)
- }
- if (KB == 0) KB = "\010";
- // check to be sure terminal is not too dumb...
- if (HO == 0) Error(sysErr,"Need ho");
- if (CD == 0 && CL == 0) Error(sysErr,"Need either cd or cl!");
- if (CM == 0) Error(sysErr,"Need cm");
- if (lines < 1 || colms < 1) {
- Error(sysErr,"Incomplete termcap entry");
- }
- if (CD == 0) CD = "\007";
- // make sure we didn't overflow buffer
- if (ptr >= &tcapbuf[TCapsLen]) {
- Error(sysErr,"Terminal description too big!");
- }
- #ifdef OSK
- // setup for raw terminal modes
- xttym = ttym; // make a copy of the vanila setup
- xttym.sg_backsp = 0; // disable editing
- xttym.sg_delete = 0;
- xttym.sg_echo = 0; // echoing
- xttym.sg_alf = 0; // auto lf's
- xttym.sg_nulls = 0; // nulls
- xttym.sg_pause = 0; // pausing
- xttym.sg_bspch = 0; // backspacing
- xttym.sg_dlnch = 0; // delete line
- xttym.sg_eorch = 0; // end of record
- xttym.sg_eofch = 0; // end of file
- xttym.sg_rlnch = 0; // redraw line
- xttym.sg_dulnch = 0;
- xttym.sg_psch = 0;
- xttym.sg_kbich = 0; // interrupting
- xttym.sg_kbach = 0;
- xttym.sg_xon = 0; // xon/xoff (might be a bad idea...)
- xttym.sg_xoff = 0;
- xttym.sg_tabcr = 0; // tab handling
- // set raw mode
- if (_ss_opt(0, &xttym) < 0) Error(sysErr,"for _ss_opt");
- // setup interceptor
- if (intercept((int (*)(...))Intercept) < 0) Error(sysErr,"for intercept");
- #endif
- #ifdef unix
- // setup for raw terminal modes
- xttym = ttym; // make a copy of the vanila setup
- //xttym.c_iflag = ???;
- //xttym.c_oflag = ???;
- //xttym.c_cflag = ???;
- xttym.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ECHOCTL|ECHOPRT|ECHOKE|ICANON);
- //xttym.c_line = ???;
- for (int i = VERASE; i <= VEOL2; i++) xttym.c_cc[i] = 0;
- if (tcsetattr(0, TCSANOW, &xttym) < 0) Error(sysErr,"for tcsetattr");
- // setup interceptor
- signal(SIGINT,(SignalHandler)Interrupt);
- #endif
- #endif
- Clear(); // clear screen
- InitChars(); // initialize terminal
- }
-
- // Destructor: restore terminal state
- Terminal::~Terminal ()
- {
- PlainPen(); // plain pen
- PenPos(lines-1,0); // bottom of screen
- ExitChars(); // de-init
- #ifdef OSK
- // restore modes
- if (_ss_opt(0, &ttym) < 0) Error(sysErr,"for _ss_opt");
- // can interception of signals
- if (intercept(0) < 0) Error(sysErr,"for intercept");
- #endif
- #ifdef unix
- // restore modes
- if (tcsetattr(0, TCSANOW, &(Terminal::ttym)) < 0) Error(sysErr,"for tcsetattr");
- // can interception of signals
- signal(SIGINT,SignalDefault);
- #endif
- }
- #ifdef MESSYDOS
- extern "C" {
- void sound(int);
- }
- void Terminal::Bell()
- {
- sound(440);
- sleep(1);
- sound(0);
- }
-
- Terminal &Terminal::put(unsigned char ch)
- {
- #ifdef BARF1
- gotoxy(ccol+1,cline+1);
- #endif
- putch(ch);
- #ifdef BARF2
- ccol++;
- if (ccol >= colms)
- {
- ccol = 0;
- cline++;
- if (cline >= lines) cline = 0;
- }
- #endif
- }
- // get a terminal key press. This function will hang and wait for a key press
- int Terminal::GetKey ()
- {
- int ch; // input key
-
- ch = kbd_getkey();
- // check posible magic keys
- switch (ch)
- {
- case K_ESC:
- case K_HOME: return escCmd;
- case K_CTLP:
- case K_UP: return upCmd;
- case K_CTLB:
- case K_LEFT: return leftCmd;
- case K_CTLF:
- case K_RIGHT: return rightCmd;
- case K_CTLN:
- case K_DOWN: return downCmd;
- // case K_CTLH:
- case K_BACK: return backCmd;
- // plain key.
- default: return ch;
- }
- }
-
- // check to see if a key has been pressed. Does not hang. Does not
- // actually read the key.
- Boolean Terminal::KeyAvailable()
- {
- if ( kbd_ready() ) return true;
- else return false;
- }
-
- // Error handler
- void Terminal::Error (ErrKind err,const char *msg)
- {
- if (errFun != 0) (*errFun)(err,msg);
- else {
- if (err == sysErr) {
- // fetch system error message for system errors
- printf("Error: %s %s\n",strerror(errno),msg);
- Interrupt();
- } else {
- printf("Error: %s %s\n",
- (err == termErr ? "Terminal" : "Memory"),
- msg);
- Interrupt();
- }
- }
- }
-
- // Write a string to the message line (bottom terminal line) in standout
- // mode
- void Terminal::Message (const char* msg)
- {
- int lastRow = lines;
- int xcline = cline;
- int xccol = ccol;
- RevsPen();
- strncpy(termBuf,msg,colms);
- register len = strlen(msg);
- if (len >= colms) {
- termBuf[len = (colms-1)] = '\0';
- while (len >= (colms-1) - 3) termBuf[--len] = '.';
- } else {
- while (len < (colms-1)) termBuf[len++] = ' ';
- termBuf[len] = '\0';
- }
- PutStrAt(lastRow-1,0,termBuf);
- PenPos(xcline,xccol); PlainPen();
- }
-
- // read in a line of text. Editing is allowed and the input is echoed.
- int Terminal::GetLine (char* buffer,int bufsize,const char* terminators)
- {
- int pos = 0;
- int nchars = 0;
- int ch;
- // save base position
- int xcline = cline;
- int xccol = ccol;
- static char spaces[bufSize+2];
-
- memset(buffer,0,bufsize); // clear out buffer
- // determine max field width
- int fieldwidth = (bufsize < (colms - xccol)
- ? bufsize : (colms - xccol));
- if (fieldwidth < 1) return(-1); // field too small
- // create a buffer of spaces (for clearing)
- memset(spaces,' ',fieldwidth);
- spaces[fieldwidth] = '\0';
- // clear out field
- PutStrAt(xcline,xccol,spaces);
- PenPos(xcline,xccol); // reset position
- for (;;) {
- ch = GetKey(); // get a key
- switch (ch) { // fan out based on key
- case escCmd : // Escape - flush buffer and start over
- memset(buffer,0,bufsize);
- PutStrAt(xcline,xccol,spaces);
- PenPos(xcline,xccol);
- nchars = 0;
- pos = 0;
- break;
- case backCmd : // backspace - delete character
- if (pos > 0) {
- strncpy(&buffer[pos-1],
- &buffer[pos],
- (nchars-pos)+1);
- PenPos(cline,ccol-1);
- put(&buffer[pos-1],
- (nchars-pos));
- put(' ');
- pos--; nchars--;
- PenPos(xcline,xccol+pos);
- } else Bell();
- break;
- case deleCmd : // delete line delete to BOF
- if (pos > 0) {
- strncpy(buffer,&buffer[pos],
- (nchars-pos)+1);
- PenPos(xcline,xccol);
- put(buffer,(nchars-pos));
- nchars -= pos;
- pos = 0;
- put(spaces,
- fieldwidth-nchars);
- PenPos(xcline,xccol+pos);
- } else Bell();
- break;
- case rightCmd : // right arrow - move right
- if (pos < nchars) {
- pos++;
- PenPos(xcline,xccol+pos);
- } else Bell();
- break;
- case leftCmd : // left arror - move left
- if (pos > 0) {
- PenPos(cline,ccol-1);
- pos--;
- } else Bell();
- break;
- default : // something else.
- // terminator??
- if (strchr(terminators,ch) != 0) {
- // yep. reset pos and return
- PenPos(xcline,xccol);
- return(nchars);
- } else if (pos == nchars && // no room?
- nchars >= fieldwidth) Bell();
- else {
- if (ch < ' ') Bell(); // funny char?
- else {
- // normal charactor. shove
- // into buffer and echo.
- buffer[pos] = ch;
- put(buffer[pos]);
- pos++;
- if (pos > nchars) nchars++;
- }
- }
- break;
- }
- }
- }
-
- // put a character at some specified place
- void Terminal::PutCharAt (int row,int col,int ch)
- {
- if (col >= colms) {
- row++;
- col = 0;
- }
- PenPos(row,col);
- char cch = ch & charMask;
- Mode m = (Mode) (ch & modeMask);
- if (m == revsPen) RevsPen();
- else if (m == defPen) PlainPen();
- put(cch);
- ccol++;
- }
-
- // Put a plain string someplace
- void Terminal::PutStrAt (int row,int col,const char* str)
- {
- int slen = strlen(str);
- int mright = colms - (col+slen);
- int right = (mright < 0 ? -mright : 0);
- int left = slen - right;
- if (left > 0) {
- PenPos(row,col);
- put((char*)str,left);
- ccol += left;
- }
- if (right > 0) {
- PenPos(row+1,0);
- put((char*)(str+left),right);
- ccol += right;
- }
- }
-
- // like above, but this is a string of chars with attributes
- void Terminal::PutStrAt (int row,int col,const short* str)
- {
- while (*str != 0) {
- PutCharAt(row,col,(int)*str);
- row = cline; col = ccol;
- str++;
- }
- }
-
- //Put a plain string in a rectangluar area. If the string is too long,
- //returns a pointer to the un-displayed tail of the string. Returns
- //NULL (0) if the string fit. Does dump wrapping (indicated with a '\'
- //and displayes non-printable characters with a '.'.
- char* Terminal::PutStrInBox(int row,int col,int width,int height,const char* str)
- {
- int rrow = 0,rcol = 0;
- PenPos(row,col);
- for (char* p = (char*)str; *p != '\0'; p++) {
- if (rcol == width) {
- put('\\');
- rcol = 0;
- rrow++;
- PenPos(row+rrow,col);
- }
- if (rrow >= height) return(p);
- else if (*p == '\n') {
- while (rcol++ < width) put(' ');
- rcol = 0;
- rrow++;
- PenPos(row+rrow,col);
- } else if (*p < ' ') {
- put('.');
- rcol++;
- ccol++;
- } else {
- put(*p);
- rcol++;
- ccol++;
- }
- }
- while (rrow < height) {
- while (rcol < width) {
- put(' ');
- rcol++;
- ccol++;
- }
- rcol = 0;
- rrow++;
- if (rrow < height) PenPos(row+rrow,col);
- }
- return(0);
- }
- #else
- // code output functions.
- static int tputc (char c) {return write(1,&c,1);}
- void Terminal::WriteCode(const char* code) {tputs(code,1,tputc);}
- void Terminal::WriteCodeLines(const char* code,int l) {tputs(code,l,tputc);}
-
- // set cursor position
- void Terminal::PenPos (int row, int col)
- {
- row = (row < 0 ? 0 : (row >= lines ? lines - 1 : row));
- col = (col < 0 ? 0 : (col >= colms ? colms - 1 : col));
- PosCode(termBuf,row+1,col+1);
- WriteCode(termBuf);
- cline = row; ccol = col;
- }
-
- // get a terminal key press. This function will hang and wait for a key press
- int Terminal::GetKey ()
- {
- char ch; // input key
- char buff[10]; // look ahead buffer
-
- for (int k = 0;;) {
- // get a character
- #ifdef unix
- while (!KeyAvailable()) ;
- #endif
- read(0,&ch,1);
- buff[k++] = ch; // save in buffer
- // check posible magic keys
- if (strncmp(buff,KD,k) == 0) {
- if (KD[k] == 0) return downCmd;
- } else if (strncmp(buff,KU,k) == 0) {
- if (KU[k] == 0) return upCmd;
- } else if (strncmp(buff,KR,k) == 0) {
- if (KR[k] == 0) return rightCmd;
- } else if (strncmp(buff,KL,k) == 0) {
- if (KL[k] == 0) return leftCmd;
- } else if (strncmp(buff,KH,k) == 0) {
- if (KH[k] == 0) return escCmd;
- } else if (strncmp(buff,KB,k) == 0) {
- if (KB[k] == 0) return backCmd;
- } else if (k > 1) { // no known prefix. must be some other key
- // sort of prefix - probably undefined function key
- Bell();
- k = 0;
- continue;
- // magic single character keys
- } else if (ch == '\016') return downCmd; // ^N
- else if (ch == '\020') return upCmd; // ^P
- else if (ch == '\006') return rightCmd; // ^F
- else if (ch == '\002') return leftCmd; // ^B
- else if (ch == '\010') return backCmd; // ^H
- else if (ch == '\177') return backCmd; // RUBOUT
- else if (ch == '\025') return deleCmd; // ^U
- // plain key.
- else return (int) ch;
- }
- }
-
- // check to see if a key has been pressed. Does not hang. Does not
- // actually read the key.
- Boolean Terminal::KeyAvailable()
- {
- #ifdef OSK
- return(_gs_rdy(0) > 0);
- #endif
- #ifdef unix
- int bytes_avail;
- ioctl(0,TIOCINQ,&bytes_avail);
- return (bytes_avail > 0);
- #endif
- }
-
- // Error handler
- void Terminal::Error (ErrKind err,const char *msg)
- {
- if (errFun != 0) (*errFun)(err,msg);
- else {
- if (err == sysErr) {
- // fetch system error message for system errors
- sprintf(termBuf,"Error: %s %s\n",strerror(errno),msg);
- write(1,termBuf,strlen(termBuf));
- Interrupt();
- } else {
- sprintf(termBuf,"Error: %s %s\n",
- (err == termErr ? "Terminal" : "Memory"),
- msg);
- write(1,termBuf,strlen(termBuf));
- Interrupt();
- }
- }
- }
-
- // Write a string to the message line (bottom terminal line) in standout
- // mode
- void Terminal::Message (const char* msg)
- {
- int lastRow = lines;
- int xcline = cline;
- int xccol = ccol;
- PenPos(lastRow,0); RevsPen();
- strncpy(termBuf,msg,colms);
- register len = strlen(msg);
- if (len >= colms) {
- termBuf[len = (colms-1)] = '\0';
- while (len >= (colms-1) - 3) termBuf[--len] = '.';
- } else {
- while (len < (colms-1)) termBuf[len++] = ' ';
- termBuf[len] = '\0';
- }
- write(1,termBuf,len);
- PenPos(xcline,xccol); PlainPen();
- }
-
- // read in a line of text. Editing is allowed and the input is echoed.
- int Terminal::GetLine (char* buffer,int bufsize,const char* terminators)
- {
- int pos = 0;
- int nchars = 0;
- int ch;
- // save base position
- int xcline = cline;
- int xccol = ccol;
- static char spaces[bufSize];
-
- memset(buffer,0,bufsize); // clear out buffer
- // determine max field width
- int fieldwidth = (bufsize < (colms - xccol)
- ? bufsize : (colms - xccol));
- if (fieldwidth < 1) return(-1); // field too small
- // create a buffer of spaces (for clearing)
- memset(spaces,' ',fieldwidth);
- // clear out field
- write(1,spaces,fieldwidth);
- PenPos(xcline,xccol); // reset position
- for (;;) {
- ch = GetKey(); // get a key
- switch (ch) { // fan out based on key
- case escCmd : // Escape - flush buffer and start over
- memset(buffer,0,bufsize);
- PenPos(xcline,xccol);
- write(1,spaces,fieldwidth);
- PenPos(xcline,xccol);
- nchars = 0;
- pos = 0;
- break;
- case backCmd : // backspace - delete character
- if (pos > 0) {
- strncpy(&buffer[pos-1],
- &buffer[pos],
- (nchars-pos)+1);
- WriteCode(BC);
- write(1,&buffer[pos-1],
- (nchars-pos));
- write(1,spaces,1);
- pos--; nchars--;
- PenPos(xcline,xccol+pos);
- } else Bell();
- break;
- case deleCmd : // delete line delete to BOF
- if (pos > 0) {
- strncpy(buffer,&buffer[pos],
- (nchars-pos)+1);
- PenPos(xcline,xccol);
- write(1,buffer,(nchars-pos));
- nchars -= pos;
- pos = 0;
- write(1,spaces,
- fieldwidth-nchars);
- PenPos(xcline,xccol+pos);
- } else Bell();
- break;
- case rightCmd : // right arrow - move right
- if (pos < nchars) {
- pos++;
- PenPos(xcline,xccol+pos);
- } else Bell();
- break;
- case leftCmd : // left arror - move left
- if (pos > 0) {
- WriteCode(BC);
- pos--;
- } else Bell();
- break;
- default : // something else.
- // terminator??
- if (strchr(terminators,ch) != 0) {
- // yep. reset pos and return
- PenPos(xcline,xccol);
- return(nchars);
- } else if (pos == nchars && // no room?
- nchars >= fieldwidth) Bell();
- else {
- if (ch < ' ') Bell(); // funny char?
- else {
- // normal charactor. shove
- // into buffer and echo.
- buffer[pos] = ch;
- write(1,&buffer[pos],1);
- pos++;
- if (pos > nchars) nchars++;
- }
- }
- break;
- }
- }
- }
-
- // put a character at some specified place
- void Terminal::PutCharAt (int row,int col,int ch)
- {
- if (col >= colms) {
- row++;
- col = 0;
- }
- PenPos(row,col);
- char cch = ch & charMask;
- Mode m = (Mode) (ch & modeMask);
- if (m == revsPen) RevsPen();
- else if (m == defPen) PlainPen();
- write(1,&cch,1);
- ccol++;
- }
-
- // Put a plain string someplace
- void Terminal::PutStrAt (int row,int col,const char* str)
- {
- int slen = strlen(str);
- int mright = colms - (col+slen);
- int right = (mright < 0 ? -mright : 0);
- int left = slen - right;
- if (left > 0) {
- PenPos(row,col);
- write(1,(char*)str,left);
- ccol += left;
- }
- if (right > 0) {
- PenPos(row+1,0);
- write(1,(char*)(str+left),right);
- ccol += right;
- }
- }
-
- // like above, but this is a string of chars with attributes
- void Terminal::PutStrAt (int row,int col,const short* str)
- {
- while (*str != 0) {
- PutCharAt(row,col,(int)*str);
- row = cline; col = ccol;
- str++;
- }
- }
-
- //Put a plain string in a rectangluar area. If the string is too long,
- //returns a pointer to the un-displayed tail of the string. Returns
- //NULL (0) if the string fit. Does dump wrapping (indicated with a '\'
- //and displayes non-printable characters with a '.'.
- char* Terminal::PutStrInBox(int row,int col,int width,int height,const char* str)
- {
- int rrow = 0,rcol = 0;
- PenPos(row,col);
- for (char* p = (char*)str; *p != '\0'; p++) {
- if (rcol == width) {
- write(1,"\\",1);
- rcol = 0;
- rrow++;
- PenPos(row+rrow,col);
- }
- if (rrow >= height) return(p);
- else if (*p == '\n') {
- while (rcol++ < width) write(1," ",1);
- rcol = 0;
- rrow++;
- PenPos(row+rrow,col);
- } else if (*p < ' ') {
- write(1,".",1);
- rcol++;
- ccol++;
- } else {
- write(1,p,1);
- rcol++;
- ccol++;
- }
- }
- while (rrow < height) {
- while (rcol < width) {
- write(1," ",1);
- rcol++;
- ccol++;
- }
- rcol = 0;
- rrow++;
- if (rrow < height) PenPos(row+rrow,col);
- }
- return(0);
- }
- #endif
-
-
-
- // process forking - very O/S dependent and posible hairy...
- #ifdef OSK
-
- extern char** environ;
-
- typedef int (*ProcFunc)(const char* modname,int parmsize,const char *parmptr,
- short type,short lang,int datasize,short prior,
- short pathcnt);
-
-
- extern "MWC" {
- int os9exec(ProcFunc procfunc,const char* modname,const char** argv,
- const char** envp,unsigned stacksize,short priority,
- short pathcnt);
- };
-
-
-
-
-
- // fork a process
- int Terminal::forkprog (const char** argv)
- {
- static char errorbuffer[512];
- // remember where we are
- int xcline = cline;
- int xccol = ccol;
- // reset position and reset terminal
- PenPos(lines-1,0);
- PlainPen();
- ExitChars();
- _ss_opt(0, &ttym);
- // try to fork the process
- int pid = os9exec(os9forkc,argv[0],argv,environ,0,0,3);
- // failure??
- if (pid < 0) {
- // yep. revert terminal and spit out a message
- int error = errno;
- _ss_opt(0, &xttym);
- InitChars();
- cline = xcline; ccol = xccol;
- sprintf(errorbuffer,"Error in fork: %s",strerror(error));
- Message(errorbuffer);
- errno = error;
- return (-1); // display not disturbed
- } else {
- // fork worked. Wait for process to finish
- int error = 0;
- while (wait(&error) == 0) ; // waiting...
- error &= 0x00FFFF; // completion status...
- // revert terminal
- _ss_opt(0, &xttym);
- InitChars();
- cline = xcline; ccol = xccol;
- // did process crash??
- if (error == 0) {
- // nope
- PenPos(xcline,xccol);
- // success, but display might be trashed
- return(1);
- } else {
- // child crashed.
- // fetch error message
- sprintf(errorbuffer,"Error in child: %s",
- strerror(error));
- Message(errorbuffer);
- // stash error code
- errno = error;
- // process crashed, but might have trashed the display
- return (0);
- }
- }
- }
- #endif
- #ifdef MESSYDOS
- #include <process.h>
- #include <string.h>
- // fork a process
- int Terminal::forkprog (const char** argv)
- {
- static char errorbuffer[512];
- // remember where we are
- int xcline = cline;
- int xccol = ccol;
- // reset position and reset terminal
- PenPos(lines-1,0);
- PlainPen();
- ExitChars();
- // try to fork the process
- int error = spawnvp(P_WAIT,argv[0],argv);
- // failure??
- error &= 0x00FFFF; // completion status...
- // revert terminal
- InitChars();
- cline = xcline; ccol = xccol;
- // did process crash??
- if (error == 0) {
- // nope
- PenPos(xcline,xccol);
- // success, but display might be trashed
- return(1);
- } else if (error < 0) {
- // child was stillborn
- error = errno;
- InitChars();
- cline = xcline; ccol = xccol;
- sprintf(errorbuffer,"Error in fork: %s",strerror(error));
- Message(errorbuffer);
- errno = error;
- return (-1); // display not disturbed
- } else {
- // child crashed.
- // fetch error message
- sprintf(errorbuffer,"Error in child: %s",
- strerror(error));
- Message(errorbuffer);
- // stash error code
- errno = error;
- // process crashed, but might have trashed the display
- return (0);
- }
- }
-
- #endif
- #ifdef unix
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <string.h>
- // fork a process
- int Terminal::forkprog (const char** argv)
- {
- pid_t child;
- int error;
- static char errorbuffer[512];
- // remember where we are
- int xcline = cline;
- int xccol = ccol;
- // reset position and reset terminal
- PenPos(lines-1,0);
- PlainPen();
- ExitChars();
- // try to fork the process
- child = fork();
- if (child < 0)
- {
- error = child;
- } else if (child > 0)
- {
- waitpid(child,&error,0);
- } else
- {
- _exit(execvp(argv[0],argv));
- }
- // failure??
- error &= 0x00FFFF; // completion status...
- // revert terminal
- InitChars();
- cline = xcline; ccol = xccol;
- // did process crash??
- if (error == 0) {
- // nope
- PenPos(xcline,xccol);
- // success, but display might be trashed
- return(1);
- } else if (error < 0) {
- // child was stillborn
- error = errno;
- InitChars();
- cline = xcline; ccol = xccol;
- sprintf(errorbuffer,"Error in fork: %s",strerror(error));
- Message(errorbuffer);
- errno = error;
- return (-1); // display not disturbed
- } else {
- // child crashed.
- // fetch error message
- sprintf(errorbuffer,"Error in child: %s",
- strerror(error));
- Message(errorbuffer);
- // stash error code
- errno = error;
- // process crashed, but might have trashed the display
- return (0);
- }
- }
-
- #endif
-
-